﻿// split cma 72hours forcast tif data into one hour a file.
// for wind , it has two bands.

#include <iostream>
#include "gdal_priv.h"
#include <string>
#include <vector>
#include <memory>
#include <stdexcept>
#include <xclox.hpp>
#include "wstringutils.h"
using namespace std;
 
using namespace xclox;

int main(int argc,char* argv[])
{
    cout << "A program to split cma 72hours forcast tif data into one hour a file." << endl;
    cout << "The wind data file (filename should contain wind/WIND/Wind string ) has two bands."<<endl;
    cout<<"The program suggest each band is one hour later, and start from 0 hour."<<endl; 
    cout<<"v1.0.0"<<endl;//2025/5/9
    cout<<"usage:yy_cma72split date8StartPos timeStartPos  /some/input.tif /out/dir/prefix"<<endl;
    cout<<"  The output will be /out/dir/prefix{YYYYMMDDHH}.tif"<<endl;
    cout<<"  date8StartPos is date(YYYYMMDD) string start position (0 based) in basename of input."<<endl;
    cout<<"  timeStartPos is time string( at least has two digit HH ) start position (0 based) in basename of input."<<endl;

    if( argc!=5 ) {
        cout<<"argc not 5"<<endl;
        return 11 ;
    }

    GDALAllRegister();
    int datePos = atof(argv[1]) ;
    int timePos = atof(argv[2]) ;
    string infilename = argv[3] ;
    string outprefix  = argv[4] ;

    string baseName = wStringUtils::getFileNameFromFilePath(infilename);
    string dateStr = baseName.substr(datePos,8);
    string hourStr = baseName.substr(timePos,2);
    Time t0( atof(hourStr.c_str()) , 0, 0);
    Date d0( 
        (int)atof(dateStr.substr(0,4).c_str()),
        (int)atof(dateStr.substr(4,2).c_str()), 
        (int)atof(dateStr.substr(6,2).c_str()) );
    DateTime dt0(d0, t0);

    cout<<"use start datetime as "<< dt0.toString("yyyy-MM-dd hh:00:00")<<endl;

    int outband = 1 ;
    if( infilename.find("Wind") != string::npos
    || infilename.find("wind") != string::npos
    || infilename.find("WIND") != string::npos) {
        cout<<"use input as wind data."<<endl;
        outband = 2 ;
    }

    GDALDataset* inds = 0 ;
    GDALDataset* dsout = 0 ;
    CPLStringList opt ;
    opt.SetNameValue("COMPRESS" , "Deflate") ;
    GDALDriver *driver = GetGDALDriverManager()->GetDriverByName( "GTiff" );

    try {
        inds = (GDALDataset*)GDALOpen(infilename.c_str(),GA_ReadOnly) ;
        if( inds==0 ) {
            throw runtime_error(string("failed to open input ")+infilename);
        }
        const int xsize = inds->GetRasterXSize();
        const int ysize = inds->GetRasterYSize() ;
        const int nbands = inds->GetRasterCount() ;

        int outFileCnt = nbands/outband;

        for(int iout = 0 ; iout < outFileCnt ;++iout ) {
            DateTime dtX = dt0 + DateTime::Hours(iout) ;
            string dtXstr = dtX.toString("yyyyMMddhh") ;
            string outnameX = outprefix+dtXstr+".tif" ;
            cout<<"start "<<outnameX<<endl;

            dsout = driver->Create( outnameX.c_str() , 
                xsize , ysize , outband ,GDT_Float32,  opt.List()) ;
            if( dsout==0 ) {
                throw runtime_error(string("failed to create out file ")+outnameX);
            }
            for(int iband = 0 ; iband < outband; ++iband ) {
                vector<float> buffer1(xsize*ysize) ;
                inds->GetRasterBand( iout*outband + iband + 1)->RasterIO(GF_Read,0,0,xsize,ysize,buffer1.data(),xsize,ysize,GDT_Float32,0,0,0) ;
                dsout->GetRasterBand( iband+1 )->RasterIO(GF_Write,0,0,xsize,ysize,buffer1.data(),xsize,ysize,GDT_Float32,0,0,0) ;
            }
            double trans[6]   ;
            inds->GetGeoTransform(trans);
            dsout->SetGeoTransform(trans);
            const char* proj = inds->GetProjectionRef() ;
            dsout->SetProjection(proj) ;
            GDALClose(dsout); dsout = 0 ;
        }
        GDALClose(inds) ;inds=0;

    }catch(exception& ex) {
        cout<<"Exception : "<<ex.what()<<endl;
        if(inds) GDALClose(inds) ;inds = 0 ;
        if(dsout) GDALClose(dsout); dsout=0;
        return 21 ;
    }

    cout<<"done"<<endl;
    return 0;
}
